﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Net.Sockets;
using System.Net;
using System.Linq;
using System.Text;
using System.Threading;
using BYServer.Filter;
using BYServer.SocketEventArgs;
using BYServer.Config;
using BYServer.Log;
using FilterData;


namespace BYServer
{
    public partial class YServer
    {
        #region Private Variable
        private bool is_start;
        private int port;
        private IPAddress ip;        
        private Socket socket_server;
        //private List<YUser> Users;
        public Hashtable Users;
        Queue<Action> QueueSendData;
        #endregion

        public MachineConnection machine_connection;

        #region Static Variable
       
        int ms = 20;
        public static bool is_test;
        #endregion

        #region Property
        public FilterDecorator Filter { get; set; }
        public YServerConfig Configuration { get; set; }
        FilterDataManager FdataManager;
        #endregion

        

        public YServer(string pathConfig)
        {
            //YServer.is_test = isTest;            
            YServerConfig.PathConfig = pathConfig;
            
            this.Configuration = new YServerConfig();
            FdataManager = new FilterDataManager();
            machine_connection = new MachineConnection();
            
            Users = new Hashtable();
            QueueSendData = new Queue<Action>();
            this.port = Configuration.Port;
            this.ip = Configuration.IPServer;          
            try
            {
                socket_server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                socket_server.Bind(new IPEndPoint(ip, port));
            }
            catch (Exception ex)
            {
                YLog.Insitance.Log(ex);
            }
        }

       
        public void Start()
        {
            is_start = true;
            socket_server.Listen(Configuration.MaxQueue);
            ThreadPool.QueueUserWorkItem(new WaitCallback(AcceptConnectThread), socket_server);
            //   ThreadPool.QueueUserWorkItem(new WaitCallback(ScanForAvailable), socket_server);
            Console.WriteLine("Server started at port = " + port);
            Console.WriteLine("Waiting Accept player...");
            //machine_connection.Connect(Configuration.IPServer, Configuration.Port_Machine);
            
            
        }
        public void Pause()
        {
            is_start = false;
        }
        public void Resume()
        {
            is_start = true;
        }
        private void AcceptConnectThread(object State)
        {
            Socket sock = State as Socket;
            Socket client;
            while (is_start)
            {
                //try
                //{
                    client = sock.Accept();
                    if (Users.Count == Configuration.MaxQueue)
                        client.Disconnect(false);
                    if (Filter != null)
                    {
                        if (Filter.Check(client) == false)
                            continue;
                    }
                    IPEndPoint ipend = client.RemoteEndPoint as IPEndPoint;
                    int IDUser = Users.Count;
                    YUser user = new YUser(client,this,ipend,IDUser);
                    Monitor.Enter(Users);
                    if (Configuration.AllowMutipleConnection == false)
                    {
                        if (Users.Contains(user))
                            Console.WriteLine("Socket từ IP đã có connect");
                        else
                            Users.Add(IDUser, user);
                    }
                    else
                        Users.Add(IDUser, user);
                    
                    Monitor.Exit(Users);

                    if (XSocketConnected != null)
                        XSocketConnected(this, new XSocketConnectedEventArgs(user));
                    user.BeginReceive();                                   
                    Console.WriteLine("Accept Connection form :" + ipend.Address + ":" + ipend.Port);
                    Console.WriteLine("So Luong Client : " + Users.Keys.Count);
                    
                //}
                //catch (Exception ex)
                //{
                //    Console.WriteLine("User Log out");
                //}
            }
        }
        
        public void Kill(YUser client)
        {           
            Console.WriteLine("Remove client ID = " + client.ID.ToString());
            Users.Remove(client.ID);
            client = null;
            Console.WriteLine("So Luong Client: " + Users.Keys.Count);
        }

        public void ClearAllSocket()
        {
            for(int i=0;i<Users.Keys.Count;i++)
            {
                Kill((YUser)Users[i]);                
            }
            System.GC.Collect();
        }
        public int GetTableID()
        {           
            return Configuration.Table_ID;            
        }


        #region Event

        public event XSocketReciveHandler XSocketRecive;
        public delegate void XSocketReciveHandler(object sender, XSocketReciveEventArgs args);
        public delegate void XSocketConnectedHandler(object sender, XSocketConnectedEventArgs args);
        public event XSocketConnectedHandler XSocketConnected;
        public delegate void XSocketSendHandler(object sender, XSocketSendMessageEventArgs args);
        public event XSocketSendHandler XSocketSendMessage;
        #endregion

    }
    
}
